package org.wcms.surrounded.utils;

import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.wcms.surrounded.Constants;
import org.wcms.surrounded.model.User;

public class Utils {

	private static final byte[] SECRET_KEY = new byte[] { 21, 4, 2, 12, 16, 42, 44, 123, 21, 9, 7, 4, 7, 7, 2, 9 }; //128 bit key
	private static final Cipher encryptor;
	private static final Cipher decryptor;
	private static final MessageDigest md;
	
	static
	{		
		try {
			encryptor = Cipher.getInstance("AES");
			decryptor = Cipher.getInstance("AES");	
			md = MessageDigest.getInstance("MD5");
		} catch (NoSuchAlgorithmException e) {
			throw new IllegalStateException("Couldn't get security algorithm on server startup", e);
		} catch (NoSuchPaddingException e) {
			throw new IllegalStateException("Couldn't get security algorithm on server startup", e);
		}
		
		
		SecretKeySpec key = new SecretKeySpec(SECRET_KEY, "AES");
		
		try {
			encryptor.init(Cipher.ENCRYPT_MODE, key);		
			decryptor.init(Cipher.DECRYPT_MODE, key);
		} catch (InvalidKeyException e) {
			throw new IllegalStateException("Failed to init Encryptor/Decryptor on server startup", e);
		}
	}
	
	
    public static String getGuidFromId(long id) {
        if (id == Constants.SURROUNDED_NEW_USER_ID) {
            return Constants.SURROUNDED_COOKIE_NEW_USER_GUID;
        } 
    
		try {
			byte[] cipheredData = encryptor.doFinal(String.valueOf(id).getBytes());			
			return Base64.encodeBytes(cipheredData, Base64.URL_SAFE);
		} catch (GeneralSecurityException e) {			
			return Constants.SURROUNDED_COOKIE_NEW_USER_GUID;
		} catch (IOException e) {
		    return Constants.SURROUNDED_COOKIE_NEW_USER_GUID;
        }		  
    }
    
    
    public static long getIdFromGuid(String guid) {
        if (Constants.SURROUNDED_COOKIE_NEW_USER_GUID.equals(guid)) {
            return Constants.SURROUNDED_NEW_USER_ID;
        } 
        
        try {
			byte[] cipheredData = Base64.decode(guid, Base64.URL_SAFE);
        	return Long.parseLong(new String(decryptor.doFinal(cipheredData)));
        } catch (NumberFormatException e) {
            return Constants.SURROUNDED_NEW_USER_ID;
        } catch (GeneralSecurityException e) {
			return Constants.SURROUNDED_NEW_USER_ID;
		} catch (IOException e) {
		    return Constants.SURROUNDED_NEW_USER_ID;
		} 
    }
    
    public static String hashPassword(String password) {
    	    	
    	md.reset();
    	md.update(password.getBytes());
    	
    	byte byteData[] = md.digest();
    	
    	//convert to hex string
    	StringBuilder hexString = new StringBuilder();
    	for (byte b : byteData) {
    		String hex=Integer.toHexString(0xff & b);
   	     	if(hex.length()==1) hexString.append('0');
   	     	hexString.append(hex);
    	}
    	
    	return hexString.toString();
    }

    public static boolean isValidEmailAddress(String address) {
        
        if (address == null) {
            return false;
        }
        
        try {
            
            // test valid characters
            new InternetAddress(address);

            // test valid structure
            String[] tokens = address.split("@");
            return tokens.length == 2 &&
                   !tokens[0].isEmpty() &&
                   !tokens[1].isEmpty();
            
        } catch (AddressException e) {
            return false;
        }
    }


	public static Cookie createCookieForUser(long id) {
		Cookie userCookie = new Cookie(Constants.SURROUNDED_COOKIE, Utils.getGuidFromId(id));
        userCookie.setMaxAge(60 * 60 * 24 * 31 /* around 1 month */);
        return userCookie;
	}
	
	public static boolean hasCookie(Cookie[] cookies) {
	        return getCookie(cookies) != null;
	    }
	    
	public static Cookie getCookie(Cookie[] cookies) {
        if (cookies == null) {
            return null;
        }
        for (Cookie cookie : cookies) {
            if (cookie.getName().equals(Constants.SURROUNDED_COOKIE)) {
                return cookie;
            }            
        }
        return null;
    }
	
	
	public static void updateUserSessionAndCookie(HttpServletRequest req, 
                HttpServletResponse resp, User user) {
        HttpSession httpSession = req.getSession();
        httpSession.setAttribute(Constants.SURROUNDED_SESSION_USER, user);
        // ok to getId because objetify already took care of it after addUser
        resp.addCookie(createCookieForUser(user.getId()));
	}
    
}
